<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>极简模拟炒股</title>
  <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.2/css/bootstrap.min.css">
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
  <style>
    body { padding: 20px; }
    .profit { color: green; font-weight: bold; }
    .loss { color: red; font-weight: bold; }
    .sortable-header {
      cursor: pointer;
      user-select: none;
      position: relative;
      padding-right: 20px !important;
    }
    .sortable-header:hover {
      background-color: rgba(255,255,255,0.1);
    }
    .sort-indicator {
      position: absolute;
      right: 5px;
      top: 50%;
      transform: translateY(-50%);
      font-size: 12px;
      opacity: 0.7;
    }
    .stock-link {
      color: #0d6efd;
      text-decoration: none;
      font-weight: 500;
    }
    .stock-link:hover {
      color: #0a58ca;
      text-decoration: underline;
    }
  </style>
</head>
<body>
<div class="container">
  <h2 class="mb-4 text-center">📈 极简模拟炒股</h2>

  <!-- 查询股票 -->
  <div class="card p-3 mb-4">
    <form id="queryForm" class="row g-3">
      <div class="col-md-4">
        <input type="text" class="form-control" id="queryCode" placeholder="输入股票代码 如 600519 或 002027" required>
      </div>
      <div class="col-md-2">
        <button type="submit" class="btn btn-info w-100">查询</button>
      </div>
    </form>
    <div id="queryResult" class="mt-3"></div>
  </div>

  <!-- 导入导出功能 -->
  <div class="card p-3 mb-4">
    <h5 class="mb-3">📁 数据管理</h5>
    <div class="row g-3 mb-3">
      <div class="col-md-3">
        <button class="btn btn-success w-100" onclick="exportData()">📤 导出持仓</button>
      </div>
      <div class="col-md-3">
        <input type="file" id="importFile" accept=".json" class="form-control" onchange="importData(event)">
      </div>
      <div class="col-md-3">
        <button class="btn btn-warning w-100" onclick="document.getElementById('importFile').click()">📥 导入持仓</button>
      </div>
      <div class="col-md-3">
        <button class="btn btn-danger w-100" onclick="clearAllData()">🗑️ 清空数据</button>
      </div>
    </div>
    <div class="row g-3">
      <div class="col-md-4">
        <h6 class="mb-2">📋 显示筛选</h6>
        <div class="btn-group w-100" role="group">
          <button type="button" class="btn btn-outline-primary active" id="showAll" onclick="toggleFilter('all')">显示全部</button>
          <button type="button" class="btn btn-outline-primary" id="showFavorites" onclick="toggleFilter('favorites')">仅关注 ⭐</button>
        </div>
      </div>
    </div>
  </div>

  <!-- 持仓表 -->
  <table class="table table-striped table-bordered text-center">
    <thead class="table-dark">
      <tr>
        <th class="sortable-header" onclick="sortTable('code')">
          股票代码 <span class="sort-indicator" id="sort-code"></span>
        </th>
        <th class="sortable-header" onclick="sortTable('name')">
          股票名称 <span class="sort-indicator" id="sort-name"></span>
        </th>
        <th class="sortable-header" onclick="sortTable('avgPrice')">
          买入均价 <span class="sort-indicator" id="sort-avgPrice"></span>
        </th>
        <th class="sortable-header" onclick="sortTable('qty')">
          持仓数量 <span class="sort-indicator" id="sort-qty"></span>
        </th>
        <th class="sortable-header" onclick="sortTable('currentPrice')">
          现价 <span class="sort-indicator" id="sort-currentPrice"></span>
        </th>
        <th class="sortable-header" onclick="sortTable('profit')">
          浮动盈亏 <span class="sort-indicator" id="sort-profit"></span>
        </th>
        <th>关注</th>
      </tr>
    </thead>
    <tbody id="portfolio"></tbody>
  </table>
</div>

<script>
  let holdings = {};
  let lastQuery = null; // 保存最近查询的股票信息
  let sortState = { field: null, direction: 'asc' }; // 排序状态
  let filterState = 'all'; // 筛选状态：'all' 或 'favorites'

  // 自动补全 sh/sz
  function normalizeCode(code) {
    code = code.trim();
    if (code.startsWith("6")) return "sh" + code;
    return "sz" + code;
  }

  // 获取股票详情页面URL
  function getStockDetailUrl(code) {
    // 移除sh/sz前缀，获取纯数字代码
    const pureCode = code.replace(/^(sh|sz)/, '');
    
    // 根据股票代码判断市场
    if (code.startsWith('sh')) {
      // 上海股票 - 使用东方财富网
      return `https://quote.eastmoney.com/sh${pureCode}.html`;
    } else {
      // 深圳股票 - 使用东方财富网
      return `https://quote.eastmoney.com/sz${pureCode}.html`;
    }
  }

  // 从 localStorage 加载持仓
  function loadHoldings() {
    let data = localStorage.getItem("holdings");
    if (data) {
      holdings = JSON.parse(data);
      renderTable();
    }
  }

  // 保存持仓到 localStorage
  function saveHoldings() {
    localStorage.setItem("holdings", JSON.stringify(holdings));
  }

  // 查询股票
  $("#queryForm").on("submit", function(e) {
    e.preventDefault();
    let code = normalizeCode($("#queryCode").val());
    fetchPrice(code, function(price, name) {
      lastQuery = { code, name, price };
      $("#queryResult").html(`
        <div class="alert alert-secondary d-flex justify-content-between align-items-center">
          <div>
            ${name} (${code}) 当前价：<b>${price}</b>
          </div>
          <div>
            <input type="number" id="buyQty" placeholder="买入数量" class="form-control d-inline-block w-auto me-2" min="1">
            <button class="btn btn-primary btn-sm" onclick="buyStock()">买入</button>
          </div>
        </div>
      `);
    });
  });

  // 买入逻辑
  function buyStock() {
    if (!lastQuery) return;
    let qty = parseInt($("#buyQty").val());
    if (!qty || qty <= 0) {
      alert("请输入买入数量");
      return;
    }
    let { code, price } = lastQuery;

    if (!holdings[code]) {
      holdings[code] = { avgPrice: price, qty: qty, currentPrice: price, name: lastQuery.name, isFavorite: false };
    } else {
      let h = holdings[code];
      let totalCost = h.avgPrice * h.qty + price * qty;
      h.qty += qty;
      h.avgPrice = totalCost / h.qty;
    }
    saveHoldings();
    renderTable();
    $("#buyQty").val("");
  }

  // 渲染表格
  function renderTable() {
    let tbody = $("#portfolio");
    tbody.empty();
    
    // 将holdings转换为数组以便排序和筛选
    let holdingsArray = [];
    for (let code in holdings) {
      let h = holdings[code];
      let profit = (h.currentPrice - h.avgPrice) * h.qty;
      
      // 应用筛选
      if (filterState === 'favorites' && !h.isFavorite) {
        continue; // 跳过非关注的股票
      }
      
      holdingsArray.push({
        code: code,
        name: h.name || '-',
        avgPrice: h.avgPrice,
        qty: h.qty,
        currentPrice: h.currentPrice || 0,
        profit: h.currentPrice ? profit : 0,
        profitClass: profit >= 0 ? "profit" : "loss",
        isFavorite: h.isFavorite || false
      });
    }
    
    // 应用排序
    if (sortState.field) {
      holdingsArray.sort((a, b) => {
        let aVal = a[sortState.field];
        let bVal = b[sortState.field];
        
        // 处理字符串排序
        if (typeof aVal === 'string' && typeof bVal === 'string') {
          aVal = aVal.toLowerCase();
          bVal = bVal.toLowerCase();
        }
        
        let result = 0;
        if (aVal < bVal) result = -1;
        else if (aVal > bVal) result = 1;
        
        return sortState.direction === 'asc' ? result : -result;
      });
    }
    
    // 渲染排序后的数据
    holdingsArray.forEach(item => {
      const favoriteIcon = item.isFavorite ? '⭐' : '☆';
      const favoriteClass = item.isFavorite ? 'text-warning' : 'text-muted';
      const stockDetailUrl = getStockDetailUrl(item.code);
      tbody.append(`
        <tr>
          <td><a href="${stockDetailUrl}" target="_blank" class="stock-link" title="查看${item.code}详情">${item.code}</a></td>
          <td><a href="${stockDetailUrl}" target="_blank" class="stock-link" title="查看${item.name}详情">${item.name}</a></td>
          <td>${item.avgPrice.toFixed(2)}</td>
          <td>${item.qty}</td>
          <td>${item.currentPrice ? item.currentPrice.toFixed(2) : '-'}</td>
          <td class="${item.profitClass}">${item.currentPrice ? item.profit.toFixed(2) : '-'}</td>
          <td>
            <button class="btn btn-sm btn-outline-warning ${favoriteClass}" onclick="toggleFavorite('${item.code}')" title="${item.isFavorite ? '取消关注' : '添加关注'}">
              ${favoriteIcon}
            </button>
          </td>
        </tr>
      `);
    });
    
    // 更新排序指示器
    updateSortIndicators();
  }
  
  // 排序表格
  function sortTable(field) {
    if (sortState.field === field) {
      // 如果点击的是同一列，切换排序方向
      sortState.direction = sortState.direction === 'asc' ? 'desc' : 'asc';
    } else {
      // 如果点击的是不同列，设置新的排序字段，默认升序
      sortState.field = field;
      sortState.direction = 'asc';
    }
    
    renderTable();
  }
  
  // 更新排序指示器
  function updateSortIndicators() {
    // 清除所有指示器
    $('.sort-indicator').text('');
    
    // 设置当前排序字段的指示器
    if (sortState.field) {
      const indicator = sortState.direction === 'asc' ? '↑' : '↓';
      $(`#sort-${sortState.field}`).text(indicator);
    }
  }
  
  // 切换关注状态
  function toggleFavorite(code) {
    if (holdings[code]) {
      holdings[code].isFavorite = !holdings[code].isFavorite;
      saveHoldings();
      renderTable();
      
      const action = holdings[code].isFavorite ? '已添加到关注' : '已取消关注';
      // 简单的提示，不使用alert以免打断用户操作
      console.log(`${code} ${action}`);
    }
  }
  
  // 切换筛选状态
  function toggleFilter(filter) {
    filterState = filter;
    
    // 更新按钮状态
    $('#showAll, #showFavorites').removeClass('active');
    if (filter === 'all') {
      $('#showAll').addClass('active');
    } else {
      $('#showFavorites').addClass('active');
    }
    
    renderTable();
  }

  // 从腾讯接口获取股价
  function fetchPrice(code, callback) {
    $.ajax({
      url: `https://qt.gtimg.cn/q=${code}`,
      dataType: "text",
      scriptCharset: "GBK",
      success: function(data) {
        let parts = data.split("~");
        if (parts.length > 4) {
          let price = parseFloat(parts[3]); // 当前价
          let name = parts[1]; // 股票名称
          if (holdings[code]) {
            holdings[code].currentPrice = price;
            if (!holdings[code].name) {
              holdings[code].name = name;
            }
            saveHoldings();
            renderTable();
          }
          if (callback) callback(price, name);
        }
      }
    });
  }

  // 定时刷新持仓股价
  setInterval(() => {
    Object.keys(holdings).forEach(c => fetchPrice(c));
  }, 30000);

  // 导出数据功能
  function exportData() {
    if (Object.keys(holdings).length === 0) {
      alert("暂无持仓数据可导出");
      return;
    }
    
    const exportData = {
      exportTime: new Date().toISOString(),
      version: "1.0",
      holdings: holdings
    };
    
    const dataStr = JSON.stringify(exportData, null, 2);
    const dataBlob = new Blob([dataStr], {type: 'application/json'});
    
    const link = document.createElement('a');
    link.href = URL.createObjectURL(dataBlob);
    link.download = `股票持仓_${new Date().toISOString().split('T')[0]}.json`;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    
    alert("持仓数据导出成功！");
  }
  
  // 导入数据功能
  function importData(event) {
    const file = event.target.files[0];
    if (!file) return;
    
    if (!file.name.endsWith('.json')) {
      alert("请选择JSON格式的文件");
      return;
    }
    
    const reader = new FileReader();
    reader.onload = function(e) {
      try {
        const importedData = JSON.parse(e.target.result);
        
        // 验证数据格式
        if (!importedData.holdings || typeof importedData.holdings !== 'object') {
          throw new Error("数据格式不正确");
        }
        
        // 验证每个持仓数据的完整性并补充缺失的字段
        for (let code in importedData.holdings) {
          const holding = importedData.holdings[code];
          if (!holding.avgPrice || !holding.qty) {
            throw new Error(`股票 ${code} 的数据不完整`);
          }
          // 为旧数据补充关注状态字段
          if (holding.isFavorite === undefined) {
            holding.isFavorite = false;
          }
        }
        
        if (confirm("导入数据将覆盖当前持仓，是否继续？")) {
          holdings = importedData.holdings;
          saveHoldings();
          renderTable();
          
          // 刷新所有股票的当前价格
          Object.keys(holdings).forEach(code => fetchPrice(code));
          
          alert(`成功导入 ${Object.keys(holdings).length} 只股票的持仓数据！`);
        }
      } catch (error) {
        alert("导入失败：" + error.message);
      }
    };
    
    reader.readAsText(file);
    // 清空文件选择，允许重复选择同一文件
    event.target.value = '';
  }
  
  // 清空所有数据
  function clearAllData() {
    if (Object.keys(holdings).length === 0) {
      alert("当前没有持仓数据");
      return;
    }
    
    if (confirm("确定要清空所有持仓数据吗？此操作不可恢复！")) {
      holdings = {};
      saveHoldings();
      renderTable();
      alert("所有持仓数据已清空");
    }
  }

  // 页面加载时恢复数据
  $(document).ready(function() {
    const saved = localStorage.getItem('holdings');
    if (saved) {
      holdings = JSON.parse(saved);
      
      // 为旧数据补充关注状态字段
      for (let code in holdings) {
        if (holdings[code].isFavorite === undefined) {
          holdings[code].isFavorite = false;
        }
      }
      
      renderTable();
    }
    
    // 初始化筛选按钮状态
    $('#showAll').addClass('active');
  });
</script>
</body>
</html>
